//
//  LXHTTPRequestManager.m
//  ProjectSource_Demo
//
//  Created by Liu on 16/3/29.
//  Copyright © 2016年 AngryBear. All rights reserved.
//

#import "LXHTTPRequestManager.h"
#import "LXNetworkConfig.h"

#import <AFNetworking/AFNetworking.h>


#if DEBUG
#define LXNetworkLog(...) NSLog(__VA_ARGS__)
#else
#define LXNetworkLog(...) {}
#endif

@interface LXHTTPRequestManager ()
{
    AFHTTPRequestOperationManager *_manager;
}
@property (nonatomic, strong) NSMutableArray *requestArray;

@end

@implementation LXHTTPRequestManager

- (instancetype)init
{
    if (self = [super init]) {
        _requestArray = [NSMutableArray array];
        _manager = [AFHTTPRequestOperationManager manager];
    }
    return self;
}

#pragma mark - Public Methods
+ (LXHTTPRequestManager *)manager
{
    static LXHTTPRequestManager *manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[LXHTTPRequestManager alloc] init];
    });
    return manager;
}

- (void)addRequest:(LXBaseRequest *)request
{
    @synchronized(self.requestArray) {
        if (![self isContainedRequest:request]) {
            [self.requestArray addObject:request];
            
            [self startWithRequest:request];
        }
    }
}

- (void)removeRequest:(LXBaseRequest *)request
{
    [request.operation cancel];
    
    @synchronized(self.requestArray) {
        [self.requestArray removeObject:request];
    }
}

#pragma mark - Private Methods
- (void)startWithRequest:(LXBaseRequest *)request
{
    NSString *baseURL = [[LXNetworkConfig defaultConfig] baseURL];
    NSString *url = [NSString stringWithFormat:@"%@%@", baseURL, [request urlString]];
    LXHTTPRequestMethod method = [request method];
    id param = [request requestParameters];
    
    _manager.requestSerializer = [AFJSONRequestSerializer serializer];
    _manager.requestSerializer.timeoutInterval = [request timeoutInterval];
    
    // if api need add custom value to HTTPHeaderField
    NSDictionary *headerFieldValueDictionary = [request httpHeader];
    if (headerFieldValueDictionary != nil) {
        for (id httpHeaderField in headerFieldValueDictionary.allKeys) {
            id value = headerFieldValueDictionary[httpHeaderField];
            if ([httpHeaderField isKindOfClass:[NSString class]] && [value isKindOfClass:[NSString class]]) {
                [_manager.requestSerializer setValue:(NSString *)value forHTTPHeaderField:(NSString *)httpHeaderField];
            } else {
                LXNetworkLog(@"Error, class of key/value in headerFieldValueDictionary should be NSString.");
            }
        }
    }
    
    if (method == LXHTTPRequestMethodGet) {
        request.operation = [_manager GET:url parameters:param success:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {
            NetworkSuccessHandle success = [request successHandle];
            success(request, responseObject);
        } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
            NetworkFailureHandle failure = [request failureHandle];
            failure(request);
        }];
    }
    else if (method == LXHTTPRequestMethodPost) {
        request.operation = [_manager POST:url parameters:param success:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {
            NetworkSuccessHandle success = [request successHandle];
            success(request, responseObject);
        } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
            NetworkFailureHandle failure = [request failureHandle];
            failure(request);
        }];
    }
    else if (method == LXHTTPRequestMethodHead) {
        request.operation = [_manager HEAD:url parameters:param success:^(AFHTTPRequestOperation * _Nonnull operation) {
            NetworkSuccessHandle success = [request successHandle];
            success(request, nil);
        } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
            NetworkFailureHandle failure = [request failureHandle];
            failure(request);
        }];
    }
    else if (method == LXHTTPRequestMethodPut) {
        request.operation = [_manager PUT:url parameters:param success:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {
            NetworkSuccessHandle success = [request successHandle];
            success(request, responseObject);
        } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
            NetworkFailureHandle failure = [request failureHandle];
            failure(request);
        }];
    }
    else if (method == LXHTTPRequestMethodDelete) {
        request.operation = [_manager DELETE:url parameters:param success:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {
            NetworkSuccessHandle success = [request successHandle];
            success(request, responseObject);
        } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
            NetworkFailureHandle failure = [request failureHandle];
            failure(request);
        }];
    }
    else if (method == LXHTTPRequestMethodPatch) {
        request.operation = [_manager PATCH:url parameters:param success:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {
            NetworkSuccessHandle success = [request successHandle];
            success(request, responseObject);
        } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
            NetworkFailureHandle failure = [request failureHandle];
            failure(request);
        }];
    }
    else {
        LXNetworkLog(@"Error, unsupport http method type!");
    }
}

- (BOOL)isContainedRequest:(LXBaseRequest *)request
{
    for (LXBaseRequest *item in self.requestArray) {
        if ([[item urlString] isEqualToString:[request urlString]] && [[item parametersString] isEqualToString:[request parametersString]]) {
            return YES;
        }
    }
    return NO;
}

@end
